What will this workshop cover?
In this workshop, the aim is to cover some basics of using variables and vectors in R. We will be covering:
- Vectors
- Introduction to functions
- Indexing
Vectors
A vector is a set of information contained together in a specific order.
To make a vector you combine variables using the c() function (more on functions later); also known as concatenation. To call the c() function we use brackets () with the numbers we want separated by a comma.
The first way of making a vector is to add the arguments you want, numbers in this case.
Run this code chunk to test it out.
vect1 <- c(1,6,19,4,9)
vect1
## [1] 1 6 19 4 9
We can also combine predefined variables and vectors together to create a new vector.
x <- 30
vect2 <- c(vect1, 22, 7, x)
vect2
## [1] 1 6 19 4 9 22 7 30
Another way of making a vector is using the colon (:), which can be done without the c function. We can tell R to select a sequence of integers from x to y, or 5 through to 10 in our example.
## [1] 5 6 7 8 9 10
We can also do some basic calculations on vectors. These occur elementwise (one element at a time).
## [1] 1.0 1.2 1.4 1.6 1.8 2.0
As you can see this divides all elements in the vector by 5.
Vector exercise 1
- Make a vector called x with integers from 8 through to 14
- Add 5 to your x vector (be sure to save as result back to x)
- Make a vector called y with variables 34, 55, 13, 71, 98, 43 and 25
- Take 12 from your y vector (be sure to save as result back to y)
- Times x vector by y
Functions: what are they and how to use them
A function is code organised together to perform a specific task. The function will take in an input, perform a task, then return an output. They are the backbone of R, which comes built in with a wide array of functions.
The function(input) format the fundamental way to call and use a function in R. function is the name of the function we are using, input is the argument or data we are passing to the function.
For example:
# running times (mins)
runTimes <- c(31, 50, 15, 19, 23, 34, 9)
# mean running time
aveRun <- mean(runTimes)
aveRun
## [1] 25.85714
# tidy up result
aveRun <- round(aveRun, digits = 2)
aveRun
## [1] 25.86
Here we are using the functions c() to concatenate, round() rounds to specific decimal places, and mean() calculates the mean.
Functions exercise
We are on a walking exercise plan, where we increase our step count by a thousand each day, starting at 1000 steps and ending on 12000.
- Make a variable called steps using the
seq() function that increases steps from 1000 to 12000 by increments of 500
- Workout how many steps we have done in total from this exercise plan
- Workout out the median amount of steps we have done on this exercise plan
- Comment your code
Indexing vectors
Indexing is a technical term for accessing elements of a vector. Think of it like selecting books from a book shelf. The vector is your book shelf, the index determines the book, or books you pick from the shelf.
To index in R you use the square brackets [] after you type the name of the vector to index from. You then put the elements you want to index in the square brackets.
Run the example code chunks to see the results:
someNumbers <- c(4, 26, 11, 15, 18, 9, 3, 1)
# indexing the 6th element
someNumbers[6]
## [1] 9
Indexing elements 1 to 4
## [1] 4 26 11 15
Dropping elements 5 to 7
## [1] 4 26 11 15 1
Indexing 1, 5, and 8
## [1] 4 18 1
Indexing exercise 1
You’ve been keeping track of how much coffee you drink each day for a two week period. We want to split this into week 1 and 2. Using the code below follow the following steps:
- Find out the mean for weekOne and WeekTwo vectors.
mean doesn’t work for weekTwo. There are two ways to fix this; one using indexing and the other adding an argument to mean. Work out both and add them to the code. Hint: ?mean() gives you a help page in R.
- Calling incorrect indexes can happen. To check the length of vector try running the
length() function on the coffee vector.
# vector with n coffee per day for two weeks
coffee <- c(3, 5, 4, 2, 3, 1, 1, 6, 2, 3, 2, 4, 2, 1)
# weeks
weekOne <- coffee[1:7]
weekTwo <- coffee[8:15]
Using indexing to change values
Using indexing you can change the value of an item, or multiple items, in a vector. This is very useful if you spot a data error and want to fix it in the code. We will using similar principles in later sessions.
Run the code below to see the example:
someNumbers <- c(4, 26, 11, 15, 18, 9, 3, 1)
# Change one item
someNumbers[8] <- 50
someNumbers
## [1] 4 26 11 15 18 9 3 50
# Change multiple
someNumbers[1:3] <- c(19, 20, 21)
someNumbers
## [1] 19 20 21 15 18 9 3 50
Indexing exercise 2
You decided to track your total monthly expenditures for the year to find out more about your monthly spending. You’re interested in your spending per quarter, biggest spending month, and lowest spending month.
- Make a variable called myExpenses with the following data: 976, 631, 1231, 1120, 1374, 873, 1244, 1398, 989, 1034, 579 and 1506. Each item represents each month, first is January spending, second is February spending etc.
- You realise the spending for some of the months is wrong. January should be 921, August should be 1419, and November should be 703. Use indexing to change the values in myExpenses so they are correct.
- Using indexing make a vector for the first quarter of the year. Call it Q1 and make sure the first three months are indexed.
- Repeat for quarters 2, 3, and 4.
- Workout the average spending for each quarter. Which had the biggest spending?
- Using the
which.max() and which.min() functions, find out which months had the highest and lowest spending. Assign the result of each to a variable (minSpend, maxSpend).
- Now you know the highest and lowest spending months, put them into a vector together called MaxMin by indexing from the myExpenses vector.
Individual coding challenge 1
You decide to calculate your commuting times over a weekly period. You decide to see if you can workout, based off your weekly commute, how much commuting you will do on average this month.
- Replicate the commute variable four times using
rep() and assign to a variable called commute_est.
- Calculate the mean of commute_est and assign to a variable called aveCommute.
- Round the value of aveCommute to two decimal places using
round() and assign to aveCommute.
- You miss timed your Tuesday commute, it should be 37 instead of 33. To make replacement easier use
sort() on commute_est, and assign to a variable called commute_sort.
- Replace the 33 values with 37 using indexing in the variable commute_sort.
- Re-calculate and round aveCommute as per instructions two and three.
- Test out the following functions on the commute_sort variable:
unique() and sort(commute, decreasing = TRUE).
commute <- c(41, 33, 44, 52, 36, 39)
# enter your code here
Individual coding challenge 2
For this individual coding challenge we will be looking at Lional Messi’s season appearances and goals from 2004-2020.
The code below has been jumbled up and will not run. Your challenge is to re-order it so it runs correctly. It should print out summary statistics for season goal ratio and age band goal ratios, as well as which year was his most and least prolific, and how many years that took him.
# print career ratio
careerGoalRatio
# which season had the worst goal ratio
season[which.max(goalRatio)]
# combine age band ratios to a vector
ageGoalRatio <- c(round(mean(teenageGoalRatio), digits = 2),
round(mean(twentiesGoalRatio), digits = 2),
round(mean(thirtiesGoalRatio), digits = 2))
# add in appearance, goal and season data
appearances <- c(9,25,36,40,51,53,55,60,50,46,57,49,52,54,50,44)
goals <- c(1,8,17,16,38,47,53,73,60,41,58,41,54,45,51,31)
season <- c(2004,2005,2006,2007,2008,2009,2010,2011,2012,
2013,2014,2015,2016,2017,2018,2019)
# which season had the best goal ratio
season[which.min(goalRatio)]
# goal ratio per age band (teenager, 20's, 30's)
teenageGoalRatio <- goalRatio[1:3]
twentiesGoalRatio <- goalRatio[4:13]
thirtiesGoalRatio <- goalRatio[14:16]
# summary results
summary(goalRatio)
summary(ageGoalRatio)
# how many years playing to reach best goal ratio
season[which.min(goalRatio)] - season[1]
# work out appearance to goal ratio per season and total career ratio
goalRatio <- round(appearances/goals, digits = 2)
careerGoalRatio <- round(sum(appearances)/sum(goals), digits = 2)
LS0tCnRpdGxlOiAiUiBXb3Jrc2hvcCAyIC0gVmVjdG9ycywgZnVuY3Rpb25zLCBhbmQgaW5kZXhpbmciCmF1dGhvcjoKICAgLSBuYW1lOiBBbmRyZXcgTW9sZXMKICAgICBhZmZpbGlhdGlvbjogTGVhcm5pbmcgRGV2ZWxvcGVyLCBEaWdpdGFsIFNraWxscyBMYWIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgdGhlbWU6IHJlYWRhYmxlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBrZWVwX21kOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRvYzogVFJVRQogICAgdG9jX2Zsb2F0OiBUUlVFCi0tLQoKIyBXaGF0IHdpbGwgdGhpcyB3b3Jrc2hvcCBjb3Zlcj8KCkluIHRoaXMgd29ya3Nob3AsIHRoZSBhaW0gaXMgdG8gY292ZXIgc29tZSBiYXNpY3Mgb2YgdXNpbmcgdmFyaWFibGVzIGFuZCB2ZWN0b3JzIGluIFIuIFdlIHdpbGwgYmUgY292ZXJpbmc6CgoqICBWZWN0b3JzCiogIEludHJvZHVjdGlvbiB0byBmdW5jdGlvbnMKKiAgSW5kZXhpbmcKCiMgSW5mb3JtYXRpb24gb24gaG93IHRoZSBzZXNzaW9uIGlzIHJ1bgoKT25lIGhvdXIgZXhlcmNpc2UgYmFzZWQgc2Vzc2lvbiB3aXRoIHR1dG9yIHN1cHBvcnQuIFlvdSB3aWxsIGJlIGdpdmVuIGV4YW1wbGUgY29kZSBmb3IgYSBwcm9ibGVtLCB0aGVuIGdpdmVuIGEgcmVsYXRlZCBleGVyY2lzZSB0byBjb21wbGV0ZS4KCiMjIFdoeSB0aGlzIHN0eWxlPwoKKiAgT25saW5lIHRyYWluaW5nIGlzIHRpcmluZyBzbyBrZWVwaW5nIHRoZSBzZXNzaW9ucyB0byBvbmUgaG91cgoqICBObyBvciBsaW1pdGVkIGRlbW9uc3RyYXRpb25zIHByb3ZpZGVkIGluIG9yZGVyIHRvIHByb3ZpZGUgbW9yZSByZWFsIHdvcmxkIGV4cGVyaWVuY2UgLSB5b3UgaGF2ZSBhIHByb2JsZW0gYW5kIHlvdSBsb29rIHVwIGhvdyB0byBzb2x2ZSBpdCwgYWRhcHRpbmcgZXhhbXBsZSBjb2RlCiogIFRyYWluZXIgc3VwcG9ydCB0byBndWlkZSB0aHJvdWdoIHByb2Nlc3Mgb2YgbGVhcm5pbmcKCiMjIFdlIHdpbGwgYmUgd29ya2luZyBpbiBwYWlyczoKCiogIE9uZSBzaGFyZXMgdGhlIHNjcmVlbiBhbmQgdGhlIG90aGVyIHJlcXVlc3RzIHJlbW90ZSBjb250cm9sLgoqICBUYWtlIHR1cm5zIG9uIHdobyB0eXBlcyBmb3IgZWFjaCBleGVyY2lzZS4KKiAgU2hhcmUgbWFya2Rvd24gZmlsZSBhdCBlbmQgb2Ygc2Vzc2lvbiB2aWEgY2hhdAoqICBJZiBwb3NzaWJsZSBoYXZlIHlvdXIgY2FtZXJhIG9uIHdoZW4gZG9pbmcgdGhlIHBhaXJlZCB3b3JrLgoKIyMgV2hhdCB0byBkbyB3aGVuIGdldHRpbmcgc3R1Y2s6CgoxKSAgQXNrIHlvdXIgdGVhbSBtZW1iZXJzCjIpICBTZWFyY2ggb25saW5lOgogICogIFRoZSBhbnN3ZXIgYm94IG9uIHRoZSB0b3Agb2YgR29vZ2xlJ3MgcmVzdWx0cyBwYWdlIAogICogIHN0YWNrb3ZlcmZsb3cuY29tIChmb3IgdGFzay1zcGVjaWZpYyBzb2x1dGlvbnMpCiAgKiAgaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vICh0b3BpYyBiYXNlZCB0dXRvcmlhbHMpCjMpICBEb24ndCBzdHJ1Z2dsZSB0b28gbG9uZyBsb29raW5nIG9ubGluZSwgYXNrIHRoZSB0cmFpbmVyIGlmIHlvdSBjYW4ndCBmaW5kIGEgc29sdXRpb24hCgoqKioKCiMgVmVjdG9ycwoKQSB2ZWN0b3IgaXMgYSBzZXQgb2YgaW5mb3JtYXRpb24gY29udGFpbmVkIHRvZ2V0aGVyIGluIGEgc3BlY2lmaWMgb3JkZXIuIAoKVG8gbWFrZSBhIHZlY3RvciB5b3UgY29tYmluZSB2YXJpYWJsZXMgdXNpbmcgdGhlIGBjKClgIGZ1bmN0aW9uIChtb3JlIG9uIGZ1bmN0aW9ucyBsYXRlcik7IGFsc28ga25vd24gYXMgY29uY2F0ZW5hdGlvbi4gVG8gY2FsbCB0aGUgYGMoKWAgZnVuY3Rpb24gd2UgdXNlIGJyYWNrZXRzICgpIHdpdGggdGhlIG51bWJlcnMgd2Ugd2FudCBzZXBhcmF0ZWQgYnkgYSBjb21tYS4gIAoKVGhlIGZpcnN0IHdheSBvZiBtYWtpbmcgYSB2ZWN0b3IgaXMgdG8gYWRkIHRoZSBhcmd1bWVudHMgeW91IHdhbnQsIG51bWJlcnMgaW4gdGhpcyBjYXNlLgoKUnVuIHRoaXMgY29kZSBjaHVuayB0byB0ZXN0IGl0IG91dC4gCmBgYHtyfQp2ZWN0MSA8LSBjKDEsNiwxOSw0LDkpCnZlY3QxCmBgYApXZSBjYW4gYWxzbyBjb21iaW5lIHByZWRlZmluZWQgdmFyaWFibGVzIGFuZCB2ZWN0b3JzIHRvZ2V0aGVyIHRvIGNyZWF0ZSBhIG5ldyB2ZWN0b3IuICAKYGBge3J9CnggPC0gMzAKdmVjdDIgPC0gYyh2ZWN0MSwgMjIsIDcsIHgpCnZlY3QyCmBgYApBbm90aGVyIHdheSBvZiBtYWtpbmcgYSB2ZWN0b3IgaXMgdXNpbmcgdGhlIGNvbG9uICg6KSwgd2hpY2ggY2FuIGJlIGRvbmUgd2l0aG91dCB0aGUgYyBmdW5jdGlvbi4gV2UgY2FuIHRlbGwgUiB0byBzZWxlY3QgYSBzZXF1ZW5jZSBvZiBpbnRlZ2VycyBmcm9tIHggdG8geSwgb3IgNSB0aHJvdWdoIHRvIDEwIGluIG91ciBleGFtcGxlLgpgYGB7cn0KdmVjdDMgPC0gNToxMAp2ZWN0MwpgYGAKV2UgY2FuIGFsc28gZG8gc29tZSBiYXNpYyBjYWxjdWxhdGlvbnMgb24gdmVjdG9ycy4gVGhlc2Ugb2NjdXIgZWxlbWVudHdpc2UgKG9uZSBlbGVtZW50IGF0IGEgdGltZSkuCmBgYHtyfQp2ZWN0My81CmBgYApBcyB5b3UgY2FuIHNlZSB0aGlzIGRpdmlkZXMgYWxsIGVsZW1lbnRzIGluIHRoZSB2ZWN0b3IgYnkgNS4KCiMjIFZlY3RvciBleGVyY2lzZSAxCgoxKSAgTWFrZSBhIHZlY3RvciBjYWxsZWQgeCB3aXRoIGludGVnZXJzIGZyb20gOCB0aHJvdWdoIHRvIDE0CjIpICBBZGQgNSB0byB5b3VyIHggdmVjdG9yIChiZSBzdXJlIHRvIHNhdmUgYXMgcmVzdWx0IGJhY2sgdG8geCkKMykgIE1ha2UgYSB2ZWN0b3IgY2FsbGVkIHkgd2l0aCB2YXJpYWJsZXMgMzQsIDU1LCAxMywgNzEsIDk4LCA0MyBhbmQgMjUgCjQpICBUYWtlIDEyIGZyb20geW91ciB5IHZlY3RvciAoYmUgc3VyZSB0byBzYXZlIGFzIHJlc3VsdCBiYWNrIHRvIHkpCjUpICBUaW1lcyB4IHZlY3RvciBieSB5CgpgYGB7cn0KIyB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIEZ1bmN0aW9uczogd2hhdCBhcmUgdGhleSBhbmQgaG93IHRvIHVzZSB0aGVtCgpBIGZ1bmN0aW9uIGlzIGNvZGUgb3JnYW5pc2VkIHRvZ2V0aGVyIHRvIHBlcmZvcm0gYSBzcGVjaWZpYyB0YXNrLiBUaGUgZnVuY3Rpb24gd2lsbCB0YWtlIGluIGFuIGlucHV0LCBwZXJmb3JtIGEgdGFzaywgdGhlbiByZXR1cm4gYW4gb3V0cHV0LiBUaGV5IGFyZSB0aGUgYmFja2JvbmUgb2YgUiwgd2hpY2ggY29tZXMgYnVpbHQgaW4gd2l0aCBhIHdpZGUgYXJyYXkgb2YgZnVuY3Rpb25zLiAgCgpUaGUgKipmdW5jdGlvbihpbnB1dCkqKiBmb3JtYXQgdGhlIGZ1bmRhbWVudGFsIHdheSB0byBjYWxsIGFuZCB1c2UgYSBmdW5jdGlvbiBpbiBSLiAqKmZ1bmN0aW9uKiogaXMgdGhlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uIHdlIGFyZSB1c2luZywgKippbnB1dCoqIGlzIHRoZSBhcmd1bWVudCBvciBkYXRhIHdlIGFyZSBwYXNzaW5nIHRvIHRoZSBmdW5jdGlvbi4gCgpGb3IgZXhhbXBsZToKYGBge3J9CiMgcnVubmluZyB0aW1lcyAobWlucykKcnVuVGltZXMgPC0gYygzMSwgNTAsIDE1LCAxOSwgMjMsIDM0LCA5KQojIG1lYW4gcnVubmluZyB0aW1lCmF2ZVJ1biA8LSBtZWFuKHJ1blRpbWVzKQphdmVSdW4KIyB0aWR5IHVwIHJlc3VsdAphdmVSdW4gPC0gcm91bmQoYXZlUnVuLCBkaWdpdHMgPSAyKQphdmVSdW4KYGBgCkhlcmUgd2UgYXJlIHVzaW5nIHRoZSBmdW5jdGlvbnMgYGMoKWAgdG8gY29uY2F0ZW5hdGUsIGByb3VuZCgpYCByb3VuZHMgdG8gc3BlY2lmaWMgZGVjaW1hbCBwbGFjZXMsIGFuZCBgbWVhbigpYCBjYWxjdWxhdGVzIHRoZSBtZWFuLgoKIyMgRnVuY3Rpb25zIGV4ZXJjaXNlCgpXZSBhcmUgb24gYSB3YWxraW5nIGV4ZXJjaXNlIHBsYW4sIHdoZXJlIHdlIGluY3JlYXNlIG91ciBzdGVwIGNvdW50IGJ5IGEgdGhvdXNhbmQgZWFjaCBkYXksIHN0YXJ0aW5nIGF0IDEwMDAgc3RlcHMgYW5kIGVuZGluZyBvbiAxMjAwMC4KCjEpICBNYWtlIGEgdmFyaWFibGUgY2FsbGVkIHN0ZXBzIHVzaW5nIHRoZSBgc2VxKClgIGZ1bmN0aW9uIHRoYXQgaW5jcmVhc2VzIHN0ZXBzIGZyb20gMTAwMCB0byAxMjAwMCBieSBpbmNyZW1lbnRzIG9mIDUwMAoyKSAgV29ya291dCBob3cgbWFueSBzdGVwcyB3ZSBoYXZlIGRvbmUgaW4gdG90YWwgZnJvbSB0aGlzIGV4ZXJjaXNlIHBsYW4KMykgIFdvcmtvdXQgb3V0IHRoZSBtZWRpYW4gYW1vdW50IG9mIHN0ZXBzIHdlIGhhdmUgZG9uZSBvbiB0aGlzIGV4ZXJjaXNlIHBsYW4KNCkgIENvbW1lbnQgeW91ciBjb2RlCgpgYGB7cn0KIyB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIEluZGV4aW5nIHZlY3RvcnMKCkluZGV4aW5nIGlzIGEgdGVjaG5pY2FsIHRlcm0gZm9yIGFjY2Vzc2luZyBlbGVtZW50cyBvZiBhIHZlY3Rvci4gVGhpbmsgb2YgaXQgbGlrZSBzZWxlY3RpbmcgYm9va3MgZnJvbSBhIGJvb2sgc2hlbGYuIFRoZSB2ZWN0b3IgaXMgeW91ciBib29rIHNoZWxmLCB0aGUgaW5kZXggZGV0ZXJtaW5lcyB0aGUgYm9vaywgb3IgYm9va3MgeW91IHBpY2sgZnJvbSB0aGUgc2hlbGYuCgohW0Rlc2lnbmVkIGJ5IG1hY3JvdmVjdG9yIC8gRnJlZXBpa10oaHR0cHM6Ly9naXRodWIuY29tL2FuZHJld21vbGVzMi9yVHJhaW5JbnRyb2R1Y3Rpb24vYmxvYi9tYXN0ZXIvV29ya3Nob3AyL2ltYWdlcy82NzE0LmpwZz9yYXc9dHJ1ZSl7d2lkdGg9MzAlfQoKVG8gaW5kZXggaW4gUiB5b3UgdXNlIHRoZSBzcXVhcmUgYnJhY2tldHMgW10gYWZ0ZXIgeW91IHR5cGUgdGhlIG5hbWUgb2YgdGhlIHZlY3RvciB0byBpbmRleCBmcm9tLiBZb3UgdGhlbiBwdXQgdGhlIGVsZW1lbnRzIHlvdSB3YW50IHRvIGluZGV4IGluIHRoZSBzcXVhcmUgYnJhY2tldHMuCgpSdW4gdGhlIGV4YW1wbGUgY29kZSBjaHVua3MgdG8gc2VlIHRoZSByZXN1bHRzOgpgYGB7cn0Kc29tZU51bWJlcnMgPC0gYyg0LCAyNiwgMTEsIDE1LCAxOCwgOSwgMywgMSkKIyBpbmRleGluZyB0aGUgNnRoIGVsZW1lbnQKc29tZU51bWJlcnNbNl0KYGBgCkluZGV4aW5nIGVsZW1lbnRzIDEgdG8gNApgYGB7cn0Kc29tZU51bWJlcnNbMTo0XQpgYGAKRHJvcHBpbmcgZWxlbWVudHMgNSB0byA3CmBgYHtyfQpzb21lTnVtYmVyc1stNTotN10KYGBgCkluZGV4aW5nIDEsIDUsIGFuZCA4CmBgYHtyfQpzb21lTnVtYmVyc1tjKDEsNSw4KV0KYGBgCgojIyBJbmRleGluZyBleGVyY2lzZSAxCllvdSd2ZSBiZWVuIGtlZXBpbmcgdHJhY2sgb2YgaG93IG11Y2ggY29mZmVlIHlvdSBkcmluayBlYWNoIGRheSBmb3IgYSB0d28gd2VlayBwZXJpb2QuIFdlIHdhbnQgdG8gc3BsaXQgdGhpcyBpbnRvIHdlZWsgMSBhbmQgMi4gVXNpbmcgdGhlIGNvZGUgYmVsb3cgZm9sbG93IHRoZSBmb2xsb3dpbmcgc3RlcHM6CgoxKSAgRmluZCBvdXQgdGhlIG1lYW4gZm9yIHdlZWtPbmUgYW5kIFdlZWtUd28gdmVjdG9ycy4KMikgIGBtZWFuYCBkb2Vzbid0IHdvcmsgZm9yIHdlZWtUd28uIFRoZXJlIGFyZSB0d28gd2F5cyB0byBmaXggdGhpczsgb25lIHVzaW5nIGluZGV4aW5nIGFuZCB0aGUgb3RoZXIgYWRkaW5nIGFuIGFyZ3VtZW50IHRvIG1lYW4uIFdvcmsgb3V0IGJvdGggYW5kIGFkZCB0aGVtIHRvIHRoZSBjb2RlLiBIaW50OiBgP21lYW4oKWAgZ2l2ZXMgeW91IGEgaGVscCBwYWdlIGluIFIuIAozKSAgQ2FsbGluZyBpbmNvcnJlY3QgaW5kZXhlcyBjYW4gaGFwcGVuLiBUbyBjaGVjayB0aGUgbGVuZ3RoIG9mIHZlY3RvciB0cnkgcnVubmluZyB0aGUgYGxlbmd0aCgpYCBmdW5jdGlvbiBvbiB0aGUgY29mZmVlIHZlY3Rvci4KCmBgYHtyfQojIHZlY3RvciB3aXRoIG4gY29mZmVlIHBlciBkYXkgZm9yIHR3byB3ZWVrcwpjb2ZmZWUgPC0gYygzLCA1LCA0LCAyLCAzLCAxLCAxLCA2LCAyLCAzLCAyLCA0LCAyLCAxKQoKIyB3ZWVrcwp3ZWVrT25lIDwtIGNvZmZlZVsxOjddCndlZWtUd28gPC0gY29mZmVlWzg6MTVdCmBgYAoKIyBVc2luZyBpbmRleGluZyB0byBjaGFuZ2UgdmFsdWVzClVzaW5nIGluZGV4aW5nIHlvdSBjYW4gY2hhbmdlIHRoZSB2YWx1ZSBvZiBhbiBpdGVtLCBvciBtdWx0aXBsZSBpdGVtcywgaW4gYSB2ZWN0b3IuIFRoaXMgaXMgdmVyeSB1c2VmdWwgaWYgeW91IHNwb3QgYSBkYXRhIGVycm9yIGFuZCB3YW50IHRvIGZpeCBpdCBpbiB0aGUgY29kZS4gV2Ugd2lsbCB1c2luZyBzaW1pbGFyIHByaW5jaXBsZXMgaW4gbGF0ZXIgc2Vzc2lvbnMuCgpSdW4gdGhlIGNvZGUgYmVsb3cgdG8gc2VlIHRoZSBleGFtcGxlOgpgYGB7cn0Kc29tZU51bWJlcnMgPC0gYyg0LCAyNiwgMTEsIDE1LCAxOCwgOSwgMywgMSkKIyBDaGFuZ2Ugb25lIGl0ZW0Kc29tZU51bWJlcnNbOF0gPC0gNTAKc29tZU51bWJlcnMKIyBDaGFuZ2UgbXVsdGlwbGUKc29tZU51bWJlcnNbMTozXSA8LSBjKDE5LCAyMCwgMjEpCnNvbWVOdW1iZXJzCmBgYAoKIyMgSW5kZXhpbmcgZXhlcmNpc2UgMgpZb3UgZGVjaWRlZCB0byB0cmFjayB5b3VyIHRvdGFsIG1vbnRobHkgZXhwZW5kaXR1cmVzIGZvciB0aGUgeWVhciB0byBmaW5kIG91dCBtb3JlIGFib3V0IHlvdXIgbW9udGhseSBzcGVuZGluZy4gWW91J3JlIGludGVyZXN0ZWQgaW4geW91ciBzcGVuZGluZyBwZXIgcXVhcnRlciwgYmlnZ2VzdCBzcGVuZGluZyBtb250aCwgYW5kIGxvd2VzdCBzcGVuZGluZyBtb250aC4KCjEpICBNYWtlIGEgdmFyaWFibGUgY2FsbGVkIG15RXhwZW5zZXMgd2l0aCB0aGUgZm9sbG93aW5nIGRhdGE6IDk3NiwgNjMxLCAxMjMxLCAxMTIwLCAxMzc0LCA4NzMsIDEyNDQsIDEzOTgsIDk4OSwgMTAzNCwgNTc5IGFuZCAxNTA2LiBFYWNoIGl0ZW0gcmVwcmVzZW50cyBlYWNoIG1vbnRoLCBmaXJzdCBpcyBKYW51YXJ5IHNwZW5kaW5nLCBzZWNvbmQgaXMgRmVicnVhcnkgc3BlbmRpbmcgZXRjLgoyKSAgWW91IHJlYWxpc2UgdGhlIHNwZW5kaW5nIGZvciBzb21lIG9mIHRoZSBtb250aHMgaXMgd3JvbmcuIEphbnVhcnkgc2hvdWxkIGJlIDkyMSwgQXVndXN0IHNob3VsZCBiZSAxNDE5LCBhbmQgTm92ZW1iZXIgc2hvdWxkIGJlIDcwMy4gVXNlIGluZGV4aW5nIHRvIGNoYW5nZSB0aGUgdmFsdWVzIGluIG15RXhwZW5zZXMgc28gdGhleSBhcmUgY29ycmVjdC4gIAozKSAgVXNpbmcgaW5kZXhpbmcgbWFrZSBhIHZlY3RvciBmb3IgdGhlIGZpcnN0IHF1YXJ0ZXIgb2YgdGhlIHllYXIuIENhbGwgaXQgUTEgYW5kIG1ha2Ugc3VyZSB0aGUgZmlyc3QgdGhyZWUgbW9udGhzIGFyZSBpbmRleGVkLgo0KSAgUmVwZWF0IGZvciBxdWFydGVycyAyLCAzLCBhbmQgNC4KNSkgIFdvcmtvdXQgdGhlIGF2ZXJhZ2Ugc3BlbmRpbmcgZm9yIGVhY2ggcXVhcnRlci4gV2hpY2ggaGFkIHRoZSBiaWdnZXN0IHNwZW5kaW5nPwo2KSAgVXNpbmcgdGhlIGB3aGljaC5tYXgoKWAgYW5kIGB3aGljaC5taW4oKWAgZnVuY3Rpb25zLCBmaW5kIG91dCB3aGljaCBtb250aHMgaGFkIHRoZSBoaWdoZXN0IGFuZCBsb3dlc3Qgc3BlbmRpbmcuIEFzc2lnbiB0aGUgcmVzdWx0IG9mIGVhY2ggdG8gYSB2YXJpYWJsZSAobWluU3BlbmQsIG1heFNwZW5kKS4KNykgIE5vdyB5b3Uga25vdyB0aGUgaGlnaGVzdCBhbmQgbG93ZXN0IHNwZW5kaW5nIG1vbnRocywgcHV0IHRoZW0gaW50byBhIHZlY3RvciB0b2dldGhlciBjYWxsZWQgTWF4TWluIGJ5IGluZGV4aW5nIGZyb20gdGhlIG15RXhwZW5zZXMgdmVjdG9yLiAKCmBgYHtyfQojIGVudGVyIHlvdXIgY29kZSBoZXJlCgpgYGAKCiMgRmluYWwgdGFzayAtIFBsZWFzZSBnaXZlIHVzIHlvdXIgaW5kaXZpZHVhbCBmZWVkYmFjayEKClRoaXMgaXMgdGhlIGZpcnN0IHRpbWUgdGhhdCB3ZSBhcmUgZXhwbG9yaW5nIGEgcmVtb3RlIGxlYXJuaW5nIGZvcm1hdCBmb3Igb3VyIHdvcmtzaG9wcyBhbmQgd2Ugd291bGQgYmUgZ3JhdGVmdWwgaWYgeW91IGNvdWxkIHRha2UgMiBtaW5zIGJlZm9yZSB0aGUgZW5kIG9mIHRoZSB3b3Jrc2hvcCB0byBnZXQgeW91ciBmZWVkYmFjayEKCmh0dHBzOi8vbHNlLmV1LnF1YWx0cmljcy5jb20vamZlL2Zvcm0vU1ZfNzdNMzVjcTFhcnhOY2ozP2NvdXJzZT1EMDQ2LVIyVkZJJnRvcGljPVImY29ob3J0PUxUMjEmbGluaz1odHRwczovL2xzZWNsb3VkLnNoYXJlcG9pbnQuY29tLzp1Oi9zL1RFQU1fQVBELURTTC1EaWdpdGFsLVNraWxscy1UcmFpbmVycy9FVk5GR0F0SndJbEtqZTZRMEpTOEVHd0JCNnYtUmZJbEM1WDRBRFh6R0pFcTR3P2U9R2NqZnlPCgpUaGUgc29sdXRpb25zIHdpbGwgYmUgYXZhaWxhYmxlIGZyb20gYSBsaW5rIGF0IHRoZSBlbmQgb2YgdGhlIHN1cnZleS4KCiMgSW5kaXZpZHVhbCBjb2RpbmcgY2hhbGxlbmdlIDEKCllvdSBkZWNpZGUgdG8gY2FsY3VsYXRlIHlvdXIgY29tbXV0aW5nIHRpbWVzIG92ZXIgYSB3ZWVrbHkgcGVyaW9kLiBZb3UgZGVjaWRlIHRvIHNlZSBpZiB5b3UgY2FuIHdvcmtvdXQsIGJhc2VkIG9mZiB5b3VyIHdlZWtseSBjb21tdXRlLCBob3cgbXVjaCBjb21tdXRpbmcgeW91IHdpbGwgZG8gb24gYXZlcmFnZSB0aGlzIG1vbnRoLgoKMSkgIFJlcGxpY2F0ZSB0aGUgY29tbXV0ZSB2YXJpYWJsZSBmb3VyIHRpbWVzIHVzaW5nIGByZXAoKWAgYW5kIGFzc2lnbiB0byBhIHZhcmlhYmxlIGNhbGxlZCBjb21tdXRlX2VzdC4KMikgIENhbGN1bGF0ZSB0aGUgbWVhbiBvZiBjb21tdXRlX2VzdCBhbmQgYXNzaWduIHRvIGEgdmFyaWFibGUgY2FsbGVkIGF2ZUNvbW11dGUuCjMpICBSb3VuZCB0aGUgdmFsdWUgb2YgYXZlQ29tbXV0ZSB0byB0d28gZGVjaW1hbCBwbGFjZXMgdXNpbmcgYHJvdW5kKClgIGFuZCBhc3NpZ24gdG8gYXZlQ29tbXV0ZS4KNCkgIFlvdSBtaXNzIHRpbWVkIHlvdXIgVHVlc2RheSBjb21tdXRlLCBpdCBzaG91bGQgYmUgMzcgaW5zdGVhZCBvZiAzMy4gVG8gbWFrZSByZXBsYWNlbWVudCBlYXNpZXIgdXNlIGBzb3J0KClgIG9uIGNvbW11dGVfZXN0LCBhbmQgYXNzaWduIHRvIGEgdmFyaWFibGUgY2FsbGVkIGNvbW11dGVfc29ydC4KNSkgIFJlcGxhY2UgdGhlIDMzIHZhbHVlcyB3aXRoIDM3IHVzaW5nIGluZGV4aW5nIGluIHRoZSB2YXJpYWJsZSBjb21tdXRlX3NvcnQuCjYpICBSZS1jYWxjdWxhdGUgYW5kIHJvdW5kIGF2ZUNvbW11dGUgYXMgcGVyIGluc3RydWN0aW9ucyB0d28gYW5kIHRocmVlLgo3KSAgVGVzdCBvdXQgdGhlIGZvbGxvd2luZyBmdW5jdGlvbnMgb24gdGhlIGNvbW11dGVfc29ydCB2YXJpYWJsZTogYHVuaXF1ZSgpYCBhbmQgYHNvcnQoY29tbXV0ZSwgZGVjcmVhc2luZyA9IFRSVUUpYC4KCmBgYHtyfQpjb21tdXRlIDwtIGMoNDEsIDMzLCA0NCwgNTIsIDM2LCAzOSkKIyBlbnRlciB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIEluZGl2aWR1YWwgY29kaW5nIGNoYWxsZW5nZSAyCgpGb3IgdGhpcyBpbmRpdmlkdWFsIGNvZGluZyBjaGFsbGVuZ2Ugd2Ugd2lsbCBiZSBsb29raW5nIGF0IExpb25hbCBNZXNzaSdzIHNlYXNvbiBhcHBlYXJhbmNlcyBhbmQgZ29hbHMgZnJvbSAyMDA0LTIwMjAuIAoKVGhlIGNvZGUgYmVsb3cgaGFzIGJlZW4ganVtYmxlZCB1cCBhbmQgd2lsbCBub3QgcnVuLiBZb3VyIGNoYWxsZW5nZSBpcyB0byByZS1vcmRlciBpdCBzbyBpdCBydW5zIGNvcnJlY3RseS4gSXQgc2hvdWxkIHByaW50IG91dCBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHNlYXNvbiBnb2FsIHJhdGlvIGFuZCBhZ2UgYmFuZCBnb2FsIHJhdGlvcywgYXMgd2VsbCBhcyB3aGljaCB5ZWFyIHdhcyBoaXMgbW9zdCBhbmQgbGVhc3QgcHJvbGlmaWMsIGFuZCBob3cgbWFueSB5ZWFycyB0aGF0IHRvb2sgaGltLiAKCmBgYHtyIGV2YWw9RkFMU0V9CiMgcHJpbnQgY2FyZWVyIHJhdGlvCmNhcmVlckdvYWxSYXRpbwoKIyB3aGljaCBzZWFzb24gaGFkIHRoZSB3b3JzdCBnb2FsIHJhdGlvCnNlYXNvblt3aGljaC5tYXgoZ29hbFJhdGlvKV0KCiMgY29tYmluZSBhZ2UgYmFuZCByYXRpb3MgdG8gYSB2ZWN0b3IKYWdlR29hbFJhdGlvIDwtIGMocm91bmQobWVhbih0ZWVuYWdlR29hbFJhdGlvKSwgZGlnaXRzID0gMiksIAogICAgICAgICAgICAgIHJvdW5kKG1lYW4odHdlbnRpZXNHb2FsUmF0aW8pLCBkaWdpdHMgPSAyKSwKICAgICAgICAgICAgICByb3VuZChtZWFuKHRoaXJ0aWVzR29hbFJhdGlvKSwgZGlnaXRzID0gMikpCgojIGFkZCBpbiBhcHBlYXJhbmNlLCBnb2FsIGFuZCBzZWFzb24gZGF0YQphcHBlYXJhbmNlcyA8LSBjKDksMjUsMzYsNDAsNTEsNTMsNTUsNjAsNTAsNDYsNTcsNDksNTIsNTQsNTAsNDQpCmdvYWxzIDwtIGMoMSw4LDE3LDE2LDM4LDQ3LDUzLDczLDYwLDQxLDU4LDQxLDU0LDQ1LDUxLDMxKQpzZWFzb24gPC0gYygyMDA0LDIwMDUsMjAwNiwyMDA3LDIwMDgsMjAwOSwyMDEwLDIwMTEsMjAxMiwKICAgICAgICAgICAgMjAxMywyMDE0LDIwMTUsMjAxNiwyMDE3LDIwMTgsMjAxOSkKCiMgd2hpY2ggc2Vhc29uIGhhZCB0aGUgYmVzdCBnb2FsIHJhdGlvCnNlYXNvblt3aGljaC5taW4oZ29hbFJhdGlvKV0KCiMgZ29hbCByYXRpbyBwZXIgYWdlIGJhbmQgKHRlZW5hZ2VyLCAyMCdzLCAzMCdzKQp0ZWVuYWdlR29hbFJhdGlvIDwtIGdvYWxSYXRpb1sxOjNdCnR3ZW50aWVzR29hbFJhdGlvIDwtIGdvYWxSYXRpb1s0OjEzXQp0aGlydGllc0dvYWxSYXRpbyA8LSBnb2FsUmF0aW9bMTQ6MTZdCgojIHN1bW1hcnkgcmVzdWx0cwpzdW1tYXJ5KGdvYWxSYXRpbykKc3VtbWFyeShhZ2VHb2FsUmF0aW8pCgojIGhvdyBtYW55IHllYXJzIHBsYXlpbmcgdG8gcmVhY2ggYmVzdCBnb2FsIHJhdGlvCnNlYXNvblt3aGljaC5taW4oZ29hbFJhdGlvKV0gLSBzZWFzb25bMV0KCiMgd29yayBvdXQgYXBwZWFyYW5jZSB0byBnb2FsIHJhdGlvIHBlciBzZWFzb24gYW5kIHRvdGFsIGNhcmVlciByYXRpbwpnb2FsUmF0aW8gPC0gcm91bmQoYXBwZWFyYW5jZXMvZ29hbHMsIGRpZ2l0cyA9IDIpCmNhcmVlckdvYWxSYXRpbyA8LSByb3VuZChzdW0oYXBwZWFyYW5jZXMpL3N1bShnb2FscyksIGRpZ2l0cyA9IDIpCmBgYAoK